﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using Interfleet.SE.UICompiler.Core;
using System.Threading;
using System.IO;
using Interfleet.SE.UICompiler.UI.Views;
using Interfleet.SE.UICompiler.UI.Models;

namespace Interfleet.SE.UICompiler.UI
{
    public partial class MainForm : Form, IUCompilerView
    {

        private delegate void ShowResultDelegate(CompileResult result);

        public MainForm()
            : this(new UICompilerModel())
        { }

        public MainForm(UICompilerModel model)
        {
            if (model == null)
            {
                throw new ArgumentNullException("model");
            }
            Model = model;
            InitializeComponent();
            SetRemoveButtonEnabled(false);
            SetCompileButtonEnabled(false);
            SetBatchButtonEnabled();
            comboBox_CompileType.SelectedItem = comboBox_CompileType.Items[1];
        }

        private UICompilerModel Model
        {
            get;
            set;
        }

        private void button_AddFile_Click(object sender, EventArgs e)
        {
            openFileDialog1.Filter = SelectedFilter;
            DialogResult result = openFileDialog1.ShowDialog();
            if (result == DialogResult.OK)
            {
                var files = openFileDialog1.FileNames;
                if (FileAlreadyExists(files))
                {
                    return;
                }
                foreach (var file in files)
                {
                    listView_Files.Items.Add(file);
                }
            }
            Refresh();
            CheckCompileButtonEnabled();
        }

        private void button_Compile_Click(object sender, EventArgs e)
        {
            saveFileDialog1.Filter = SelectedFilter;
            DialogResult dialogResult = saveFileDialog1.ShowDialog();
            if (dialogResult != DialogResult.OK)
            {
                return;
            }
            textBox_Output.Text = "Compiling...";
            OnCompile(BuildArguments());
        }

        private void ShowResult(CompileResult result)
        {
            StringBuilder sb = new StringBuilder();
            if (result.Success)
            {
                SetBatchButtonEnabled();
                textBox_Output.ForeColor = Color.DarkGreen;
                sb.AppendLine(string.Format("Compilation done - {0}", DateTime.Now.ToString("yyyy-MM-dd HH:mm")));
                sb.AppendLine("Initial total filesize: " + result.InitialFileSize);
                sb.AppendLine("Compiled filesize: " + result.CompiledFileSize);
                sb.AppendLine("==============================");
            }
            else
            {
                textBox_Output.ForeColor = Color.Red;
                sb.AppendLine("Compilation failed");
                sb.AppendLine("==============================");
            }
            
            sb.AppendLine(result.StatusMessage);
            textBox_Output.Text = sb.ToString();
            textBox_Output.Refresh();
        }

        void closureCompilerAgent_CompilationDone(CompileResult result)
        {
            Invoke(new ShowResultDelegate(ShowResult), result);
        }

        private Arguments BuildArguments()
        {
            var args = Model.CreateArguments(SelectedCompileType);
            foreach (ListViewItem file in listView_Files.Items)
            {
                args.Files.Add(file.SubItems[0].Text);
            }
            args.CompiledFileName = saveFileDialog1.FileName;
            if (comboBox_CompileType.SelectedItem != null)
            {
                args.CompileOption = comboBox_CompileType.SelectedItem.ToString();
            }
            return args;
        }

        private void listView_Files_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (listView_Files.SelectedIndices != null && listView_Files.SelectedIndices.Count > 0)
            {
                SetRemoveButtonEnabled(true);
            }
            else
            {
                SetRemoveButtonEnabled(true);
            }
        }

        private void SetRemoveButtonEnabled(bool enabled)
        {
            button_RemoveFile.Enabled = enabled;
        }

        private void SetCompileButtonEnabled(bool enabled)
        {
            button_Compile.Enabled = enabled;
        }

        private void CheckCompileButtonEnabled()
        {
            button_Compile.Enabled = (listView_Files.Items.Count > 0) ;
        }

        private void SetBatchButtonEnabled()
        {
            if(listView_Files.Items.Count > 0 && !string.IsNullOrEmpty(saveFileDialog1.FileName) )
            {
                button_SaveBatch.Enabled = true;
            }
            else
            {
                button_SaveBatch.Enabled = false;
            }
        }

        private bool FileAlreadyExists(string[] fileNames)
        {
            foreach (ListViewItem item in listView_Files.Items)
            {
                foreach (var fileName in fileNames)
                {
                    if (item.Text == fileName)
                    {
                        MessageBox.Show(string.Format("The file {0} already exists in the list", fileName));
                        return true;
                    }
                }
            }
            return false;
        }

        private void button_RemoveFile_Click(object sender, EventArgs e)
        {
            DialogResult result = MessageBox.Show("Do you want to remove the selected files?", "Delete", MessageBoxButtons.YesNo, MessageBoxIcon.Question);
            if (result == DialogResult.No)
            {
                return;
            }
            foreach (var item in listView_Files.SelectedItems)
            {
                listView_Files.Items.Remove((ListViewItem)item);
            }
            CheckCompileButtonEnabled();
            listView_Files.Refresh();
        }

        private void button_Clear_Click(object sender, EventArgs e)
        {
            DialogResult result = MessageBox.Show("Do you want to clear the list of files?", "Clear", MessageBoxButtons.YesNo, MessageBoxIcon.Question);
            if (result == DialogResult.No)
            {
                return;
            }
            listView_Files.Items.Clear();
            CheckCompileButtonEnabled();
        }

        private void button_Exit_Click(object sender, EventArgs e)
        {
            DialogResult result = MessageBox.Show("Do you want to exit?", "Exit", MessageBoxButtons.YesNo, MessageBoxIcon.Question);
            if (result == DialogResult.No)
            {
                return;
            }
            Close();
        }

        private CompileType SelectedCompileType
        {
            get
            {
                switch (comboBox_Compiler.SelectedIndex)
                {
                    case 0:
                        return CompileType.ClosureCompilerREST;
                    case 1:
                        return CompileType.ClosureCompilerLocal;
                    case 2:
                        return CompileType.YUICompressorCss;
                    case 3:
                        return CompileType.YUICompressorJavaScript;
                    default:
                        return CompileType.ClosureCompilerREST;
                }
            }
        }

        private string SelectedFilter
        {
            get
            {
                switch (SelectedCompileType.EntityType)
                {
                    case CompileEntityType.JavaScript:
                        return "Javascript files (*.js)|*.js";
                    case CompileEntityType.Css:
                        return "Stylesheets (*.css)|*.css";
                }
                return "Javascript files (*.js)|*.js";
            }
        }


        #region IClosureCompiler Members
        private event Handlers.CompileHandler _compile;
        event Handlers.CompileHandler IUCompilerView.Compile
        {
            add { _compile += value; }
            remove { _compile -= value; }
        }

        private void OnCompile(Arguments args)
        {
            if (_compile != null)
            {
                _compile(this, new CompileEventArgs(args, SelectedCompileType));
            }
        }

        private event Handlers.CompileTypeChangedHandler _compileTypeChanged;
        event Handlers.CompileTypeChangedHandler IUCompilerView.CompileTypeChanged
        {
            add { _compileTypeChanged += value; }
            remove { _compileTypeChanged -= value; }
        }

        private void OnCompileTypeChanged()
        {
            if (_compileTypeChanged != null)
            {
                _compileTypeChanged(this, new CompileTypeChangedEventArgs(SelectedCompileType));
            }
        }

        void IUCompilerView.ShowResult(CompileResult result)
        {
            if (this.InvokeRequired)
            {
                Invoke(new ShowResultDelegate(ShowResult), result);
            }
            else
            {
                ShowResult(result);
            }
        }

        void IUCompilerView.SetCompileOptionList(CompileOptions options)
        {
            comboBox_CompileType.Items.Clear();
            if (options.Options.Count() > 0)
            {
                foreach (var option in options.Options)
                {
                    comboBox_CompileType.Items.Add(option);
                }
                comboBox_CompileType.SelectedIndex = options.PreselectedIndex;
            }
        }

        void IUCompilerView.SetCompileType(CompileType compileType)
        {
            string title = string.Empty;
            switch (compileType.Supplier)
            {
                case CompileSupplier.ClosureCompilerLocal:
                    comboBox_Compiler.SelectedIndex = 1;
                    break;
                case CompileSupplier.ClosureCompilerREST:
                    comboBox_Compiler.SelectedIndex = 0;
                    break;
                case CompileSupplier.YUICompressorCss:
                    comboBox_Compiler.SelectedIndex = 2;
                    break;
                case CompileSupplier.YUICompressorJavaScript:
                    comboBox_Compiler.SelectedIndex = 3;
                    break;
                default:
                    break;
            }
            switch (compileType.EntityType)
            {
                case CompileEntityType.JavaScript:
                    title = "JavaScript files";
                    break;
                case CompileEntityType.Css:
                    title = "Css files";
                    break;
                default:
                    title = "Files";
                    break;
            }
            groupBox1.Text = title;
            groupBox1.Refresh();
        }

        void IUCompilerView.SetArguments(Arguments arguments)
        {
            ((IUCompilerView)this).SetCompileType(arguments.CompileType);
            listView_Files.Items.Clear();
            foreach (var file in arguments.Files)
            {
                listView_Files.Items.Add(file);
            }
            if (comboBox_CompileType.Items.Count > 0)
            {
                comboBox_CompileType.SelectedItem = arguments.CompileOption;
            }
        }

        #endregion

        private void comboBox_Compiler_SelectedIndexChanged(object sender, EventArgs e)
        {
            OnCompileTypeChanged();
        }

        private void button_SaveBatch_Click(object sender, EventArgs e)
        {
            saveFileDialog1.Filter = "Xml files (*.xml)|*.xml";
            var result = saveFileDialog1.ShowDialog();
            if (result == DialogResult.OK)
            {
                var args = BuildArguments();
                Model.SaveAsBatch(saveFileDialog1.FileName, args);
                MessageBox.Show("Batchfile saved", "Batch", MessageBoxButtons.OK, MessageBoxIcon.Information);
            }
        }

        private void button_OpenBatch_Click(object sender, EventArgs e)
        {
            openFileDialog1.Filter = "Xml files (*.xml)|*.xml";
            openFileDialog1.Title = "Open batch file";
            var result = openFileDialog1.ShowDialog();
            if (result == DialogResult.OK)
            {
                // TODO: do this via the controller
                var args = Model.OpenBatch(openFileDialog1.FileName);
                ((IUCompilerView)this).SetArguments(args);
                SetCompileButtonEnabled(true);
            }
        }
    }
}
